package com.dahuyou.domain.service;

import com.dahuyou.domain.model.vo.GenerateContext;
import com.dahuyou.domain.model.vo.SourceObjInfo;
import com.dahuyou.domain.model.vo.TargetObjInfo;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiMethod;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 抽象类，提供模板方法
 */
public abstract class AbstractMap2ObjGenerator implements IMap2ObjGenerator {
    /**
     * 提取属性名称使用 ，如setXyz（）则xyz就是属性名称了
     */
    protected final String setRegex = "set(\\w+)";

    /**
     * 模板方法
     * @param project
     * @param dataContext
     * @param psiFile
     */
    @Override
    public void doGenerate(Project project, DataContext dataContext, PsiFile psiFile) {
        // 1: 获取用户所在的上下文信息，为后续获取相关信息做准备
        GenerateContext generateContext = generateUserContext(project, dataContext, psiFile);
        // 2: 获取要设置属性值的目标对象，从中获取其属性信息
        TargetObjInfo targetObjInfo = generateTargetObjInfo(generateContext);
        // 3：获取map源对象信息
        SourceObjInfo sourceObjInfo = generateSourceObjInfo(generateContext);
        // 4：织入set代码
        weavingSetCode(targetObjInfo, sourceObjInfo, generateContext);
    }

    /**
     * 织入代码
     * @param targetObjInfo
     * @param sourceObjInfo
     * @param generateContext
     */
    protected abstract void weavingSetCode(TargetObjInfo targetObjInfo, SourceObjInfo sourceObjInfo, GenerateContext generateContext);

    /**
     *
     * @param generateContext
     * @return
     */
    protected abstract SourceObjInfo generateSourceObjInfo(GenerateContext generateContext);

    /**
     *
     * @param generateContext
     * @return
     */
    protected abstract TargetObjInfo generateTargetObjInfo(GenerateContext generateContext);

    /**
     *
     * @param project
     * @param dataContext
     * @param psiFile
     * @return
     */
    protected abstract GenerateContext generateUserContext(Project project, DataContext dataContext, PsiFile psiFile);

    protected List<PsiClass> getPsiClassLinkList(PsiClass psiClass) {
        List<PsiClass> psiClassList = new ArrayList<>();
        PsiClass currentClass = psiClass;
        while (null != currentClass && !"Object".equals(currentClass.getName())) {
            psiClassList.add(currentClass);
            currentClass = currentClass.getSuperClass();
        }
        Collections.reverse(psiClassList);
        return psiClassList;
    }

    protected List<String> getMethods(PsiClass psiClass, String regex, String typeStr) {
        PsiMethod[] methods = psiClass.getMethods();
        List<String> methodList = new ArrayList<>();
        // 判断使用了 lombok，需要补全生成 get、set
        if (isUsedLombok(psiClass)) {
            PsiField[] fields = psiClass.getFields();
            for (PsiField psiField : fields) {
                String name = psiField.getName();
                methodList.add(typeStr + name.substring(0, 1).toUpperCase() + name.substring(1));
            }
            for (PsiMethod method : methods) {
                String methodName = method.getName();
                if (Pattern.matches(regex, methodName) && !methodList.contains(methodName)) {
                    methodList.add(methodName);
                }
            }
            return methodList;
        }
        for (PsiMethod method : methods) {
            String methodName = method.getName();
            if (Pattern.matches(regex, methodName)) {
                methodList.add(methodName);
            }
        }
        return methodList;
    }

    private boolean isUsedLombok(PsiClass psiClass) {
        return null != psiClass.getAnnotation("lombok.Data");
    }

}
